<?php

namespace app\api\service\ai;


use app\api\model\AiCompletions;
use app\api\model\AiCompletionsDetail;

abstract class Base
{
    protected $completionsUrl;

    protected $type;

    public function create($model, $title)
    {
        return (new AiCompletions)->insertGetId(
            [
                'type'         => $this->type,
                'model'        => $model,
                'user_id'      => 0,
                'title'        => mb_substr($title, 0, 100),
                'created_time' => time(),
                'updated_time' => time(),
            ]
        );
    }

    public function history($model, $page, $pageSize)
    {
        $list = (new AiCompletions)
            ->where('type', $this->type)
            ->where('model', $model)
            ->where('mark', 1)
            ->order('updated_time', 'desc')
            ->limit(($page - 1) * $pageSize, $pageSize)
            ->select();
        foreach ($list as &$val) {
            $today = strtotime('today');
            if ($val['updated_time'] > $today) {
                $val['group'] = '今天';
            } elseif ($val['updated_time'] > $today - 6 * 86400) {
                $val['group'] = '7 天内';
            } else {
                $val['group'] = date('Y-m', $val['updated_time']);
            }
        }

        return $list;
    }

    public function conversationHistory($chatId, $lastId, $pageSize)
    {
        $query = (new AiCompletionsDetail)
            ->where('chat_id', $chatId)
            ->order('id', 'desc');
        if ($lastId) {
            $query->where('id', '<', $lastId);
        }
        $list = $query->limit($pageSize)->select();
        foreach ($list as &$val) {
            $val = $val->toArray();
            if ($val['content_type'] == 'json') {
                $content        = json_decode($val['content'], true);
                $val['content'] = '';
                $val['img']     = [];
                foreach ($content as $v) {
                    if ($v['type'] == 'text') {
                        $val['content'] .= $v['text'];
                    } else {
                        $val['img'][] = $v['image_url']['url'];
                    }
                }
            }
        }

        return $list;
    }

    protected function completionsRequest(string $id, $content, string $model, $apiKey = null, $postFields = null): void
    {
        $history = (new AiCompletionsDetail)
            ->where('chat_id', $id)
            ->order('id', 'desc')
            ->limit(20)
            ->select();
        $messages = [];
        foreach ($history as $val) {
            array_unshift($messages, ['role' => $val['role'], 'content' => $val['content']]);
        }
        $messages[] = ['role' => 'user', 'content' => $content];
        if (is_callable($postFields)) {
            $postFields = $postFields($messages);
        } else {
            $postFields = json_encode(
                [
                    'model'    => $model,
                    'messages' => $messages,
                    'stream'   => true
                ]
            );
        }
        if (is_array($apiKey)) {
            $header = $apiKey;
        } else {
            $header = [
                'Content-Type: application/json',
                'Accept: application/json',
                'Authorization: Bearer ' . $apiKey
            ];
        }
        header('Content-Type: text/event-stream; charset=utf-8');
        header('Cache-Control: no-cache');
        header('X-Accel-Buffering: no');
        $response = '';
        $curl     = curl_init();
        curl_setopt_array(
            $curl,
            [
                CURLOPT_URL            => $this->completionsUrl,
                CURLOPT_RETURNTRANSFER => false,
                CURLOPT_ENCODING       => '',
                CURLOPT_MAXREDIRS      => 10,
                CURLOPT_TIMEOUT        => 0,
                CURLOPT_FOLLOWLOCATION => true,
                CURLOPT_HTTP_VERSION   => CURL_HTTP_VERSION_1_1,
                CURLOPT_CUSTOMREQUEST  => 'POST',
                CURLOPT_POSTFIELDS     => $postFields,
                CURLOPT_HTTPHEADER     => $header,
                CURLOPT_WRITEFUNCTION  => function ($ch, $data) use (&$response) {
                    $response .= $data;
                    echo $data;
                    ob_flush();
                    flush();

                    return strlen($data);
                },
                CURLOPT_HEADERFUNCTION => function ($ch, $header) use (&$statusCode) {
                    if (preg_match('/HTTP\/\d\.\d (\d+)/', $header, $matches)) {
                        $statusCode = $matches[1];
                    }

                    return strlen($header);
                }
            ]
        );
        ob_clean();
        curl_exec($curl);
        if (curl_errno($curl)) {
            echo "data: [ERROR] " . curl_error($curl) . "\n\n";
            echo "data: [DONE]\n\n";
            ob_flush();
            flush();
        }
        if ($statusCode >= 400) {
            $errorMsg = json_encode(
                [
                    'error' => [
                        'message' => "API请求失败 (状态码: $statusCode)",
                        'type'    => 'http_error'
                    ]
                ]
            );
            echo "data: $errorMsg\n\n";
            echo "data: [DONE]\n\n";
            ob_flush();
            flush();
        }
        curl_close($curl);
        $completionId = '';
        if ($response) {
            $assistant = '';
            foreach (explode("\n\n", $response) as $val) {
                $data = trim(substr($val, 5));
                if ($data && $data != '[DONE]') {
                    $r = json_decode($data, true);
                    if (!$completionId) {
                        $completionId = $r['id'];
                    }
                    if ($r && !empty($r['choices'])) {
                        foreach ($r['choices'] as $v) {
                            if (!empty($v['delta']['content'])) {
                                $assistant .= $v['delta']['content'];
                            }
                        }
                    }
                }
            }
            if ($assistant) {
                $insert = [
                    ['chat_id' => $id, 'completion_id' => $completionId, 'role' => 'user', 'content' => is_array($content) ? json_encode($content) : $content, 'content_type' => is_array($content) ? 'json' : 'text'],
                    ['chat_id' => $id, 'completion_id' => $completionId, 'role' => 'assistant', 'content' => $assistant, 'content_type' => 'md'],
                ];
                (new AiCompletionsDetail)->insertAll($insert);
            }
        }
        exit;
    }
}
